from subprocess import Popen, PIPE
import logging
from PIL import Image

log = logging.getLogger()

logging.basicConfig(level=logging.INFO)

def ps2epsi(fname, psepsi_p = '/usr/bin/ps2epsi'):
    """
    Run ps2epsi on supplied fname and return path to epsi file
    """
    target_fname = fname.replace('.ps','.eps')
    log.info("PS->EPSI %s", fname)
    args = [psepsi_p, fname, target_fname]
    p = Popen(
            args = args,
            shell = False,
            stdout = PIPE,
            stderr = PIPE,
            close_fds = True
            )
    stdout,stderr = p.communicate()
    if p.returncode != 0:
        log.error(' failed: %s stdout="%s" stderr="%s"', args, stderr, stdout)
        raise RuntimeError('ps2epsi failure')
    return target_fname
def ps2png(fnames, dpi = 300):
    gimp_scm = """
   (define (ps2png               filename
                              dpi
                              outfile)
  (file-ps-load-setargs dpi 0 0 1 "1"  4  1 1)
  (let* ((image (car (gimp-file-load RUN-NONINTERACTIVE filename filename)))
         (drawable (car (gimp-image-get-active-layer image))))

    (file-png-set-defaults 0 9 1 0 0 1 1 1 1)
    (gimp-file-save RUN-NONINTERACTIVE image drawable outfile outfile)
    (gimp-image-delete image)
    )
)
"""
    from os.path import basename
    log.info('converting to png using gimp %s', fnames)
    p = Popen(
        args  = ['gimp','-i','-b','-'],
        stdout = PIPE,
        stderr = PIPE,
        stdin = PIPE,
        close_fds = True,
        shell = False
        )
    
    target_fnames = [basename(fname)+".png" for fname in fnames]

    gimp_cmd = gimp_scm + "\n".join(
                [
                    "(ps2png \"%s\" %s \"%s\")"%(fname, dpi, target_fname) 
                    for fname, target_fname in zip(fnames, target_fnames)
                ]
            ) + "\n(gimp-quit 0)\n"
    print gimp_cmd
    stdout, stderr = p.communicate( gimp_cmd)
    log.info("Gimp said: %s, %s",stdout, stderr)
    if p.returncode != 0:
        raise RuntimeError('Gimp failed')
    return target_fnames
def loadpng(fname):
    """Load the given epsi file as PIL Image using resolution dpi
    """
    log.info("Loading %s",fname)
    img = Image.open(fname)
    return img
def compose(left_side, right_side, spacing, draw_line=0):
    """
    Place the two images spacing pixels left resp right of vertical axis. Draw this axis with draw_line pixels thickness (omit line if 0)
    Return a PIL Image with this composition
    """
    from PIL.ImageDraw import Draw
    w1,h1 = left_side.size
    w2,h2 = right_side.size
    assert ( (w1,h1) == (w2,h2))
    w_final  = w1+w2+2*spacing
    h_final = max(h1,h2)+2
    res = Image.new("RGB", (w_final, h_final), color=(255,255,255))
    center_w = int(w_final/2)

    #place left side at center_w - w1 - spacing, h_final/2 - h1/2
    res.paste(left_side, (center_w - w1 - spacing, h_final/2 - h1/2))
    #place right side at center_w + spacing, h_final/2 - h2/2
    res.paste(right_side, (center_w + spacing, h_final/2 - h2/2 ))
    if draw_line > 0:
        #draw the center line
        canvas = Draw(res)
        canvas.rectangle( ( (center_w - draw_line/2,0), (center_w + draw_line/2, h_final) ) , fill=0)
        del canvas

    return res

if __name__ == "__main__":
    from optparse import OptionParser
    usage = """%prog PROJECT
    Arrange ps files from kicad plot into printable pictures for toner transfer
    """
    p = OptionParser(usage=usage)
    p.add_option('-t','--thickness', dest='thickness', help='thicknes of pcb board in mm. Determines width of center line', default=1.6)
    p.add_option('-r','--dpi', dest='dpi', help='dpi to use', default=600)
    p.add_option('-d','--old-style', dest="oldstyle", default=False)
    options, args = p.parse_args()
    project = args.pop()
    DPI = int(options.dpi)
    if options.oldstyle:
        copper="Copper"
        comp = "Component"
    else:
        copper = "Back"
        comp = "Front"

    thickness = float(options.thickness)
    line_thickness = int(thickness /25.4  * DPI) + 1

    #Load copper and component
    fnames =  [(part, "%s-%s.ps" %(project, part)) for part in (copper, comp, "SilkS_Front", "SilkS_Back")]
    #Convert to epsi
    fnames = [ (part, ps2epsi(fname)) for part,fname in fnames]
    #Convert to png
    
    png_names = zip(
        [ x[0] for x in fnames],
        ps2png( [ x[1] for x in fnames], dpi = DPI)
        )
    images = dict( (x[0], loadpng(x[1])) for x in png_names)
    compose( 
            images[comp].transpose(Image.FLIP_TOP_BOTTOM), 
            images[copper].transpose(Image.ROTATE_180), 
            spacing=line_thickness,
            draw_line=line_thickness
    ).save(project+"_printme.png")
    compose( 
            images['SilkS_Back'].transpose(Image.FLIP_TOP_BOTTOM), 
            images['SilkS_Front'].transpose(Image.ROTATE_180), 
            spacing=line_thickness,
            draw_line=line_thickness
    ).transpose(Image.FLIP_LEFT_RIGHT).save(project+"_printme-Silk.png")

